package ioc;
import java.beans.Introspector;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class MiniApplicationContext {
    private final Map<String, Method> beanDefinitions = new HashMap<>();
    private final Map<String, Object> singletons = new ConcurrentHashMap<>();
    private final Object configInstance;

    public MiniApplicationContext(Class<?> configClass) throws Exception {
        if (!configClass.isAnnotationPresent(Configuration.class))
            throw new IllegalArgumentException("缺少 @Configuration");
        configInstance = configClass.getDeclaredConstructor().newInstance();
        parse(configClass);
        // 立即创建所有单例
        for (String name : beanDefinitions.keySet()) getBean(name);
    }

    @SuppressWarnings("unchecked")
    public <T> T getBean(String name) {
        return (T) singletons.computeIfAbsent(name, this::createBean);
    }

    public <T> T getBean(Class<T> type) {
        String[] names = beanDefinitions.entrySet()
                .stream()
                .filter(e -> type.isAssignableFrom(e.getValue().getReturnType()))
                .map(Map.Entry::getKey)
                .toArray(String[]::new);
        if (names.length == 0)
            throw new RuntimeException("找不到类型 " + type);
        if (names.length > 1)
            throw new RuntimeException("找到多个类型 " + type);
        return getBean(names[0]);
    }



    // 添加一个获取Bean数量的方法
    public int getBeanCount() {
        return beanDefinitions.size();
    }

    private void parse(Class<?> configClass) {
        for (Method m : configClass.getDeclaredMethods()) {
            if (m.isAnnotationPresent(Bean.class)) {
                String name = m.getAnnotation(Bean.class).name();
                if (name.isEmpty()) name = Introspector.decapitalize(m.getName());
                beanDefinitions.put(name, m);
            }
        }
    }

    private Object createBean(String name) {
        try {
            Method m = beanDefinitions.get(name);
            Object[] args = Arrays.stream(m.getParameters())
                    .map(p -> getBean(p.getType()))
                    .toArray();
            return m.invoke(configInstance, args);
        } catch (Exception e) {
            throw new RuntimeException("创建 bean[" + name + "] 失败", e);
        }
    }
}